package com.cgg.stock.user.interceptor;

import cn.hutool.core.bean.BeanUtil;
import com.cgg.stock.common.annotation.SkipToken;
import com.cgg.stock.common.exception.TokenException;
import com.cgg.stock.user.vo.dto.LoginUserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * token拦截器
 */
@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**
         * 1.获取处理请求接口上是否包含@SkipToken注解，如果有，并且value为true，表示该接口不需要token认证，直接放行
         * 2.如果没有@SkipToken注解，需要token认证，从请求头获取前端传递token
         * 3.如果没有，抛异常，交给全局异常处理器
         * 4.如果有，根据token到redis获取用户信息，
         *     （1）如果没有，抛异常
         *     （2）如果有，token认证通过，放行
         */

        //HandlerMethod  表示Controller类的处理请求的方法对象
        if (!(handler instanceof HandlerMethod)){
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        //判断方法上是否有SkipToken注解
        if (handlerMethod.getMethod().isAnnotationPresent(SkipToken.class)){
            SkipToken annotation = handlerMethod.getMethod().getAnnotation(SkipToken.class);
            //获取SkipToken注解对象的value属性，为true
            if (annotation.value()){
                //不需要token认证，直接放行
                return true;
            }
        }

        //如果没有@SkipToken注解，需要token认证，从请求头获取前端传递token
        String token = request.getHeader("token");
        //如果没有，抛异常，交给全局异常处理器
        if (StringUtils.isEmpty(token)){
            throw new TokenException("没有token，请重新登录");
        }

        //如果有，根据token到redis获取用户信息，
        String key = "loginUser:"+token;
        if (redisTemplate.hasKey(key)){


            Map entries = redisTemplate.opsForHash().entries(key);

            //把map转换为LoginUserDTO，后期扩展一些，根据UserId查询用户的权限
            LoginUserDTO loginUserDTO = BeanUtil.fillBeanWithMap(entries, new LoginUserDTO(), true);

            // TODO: 2023/1/3 根据UserId查询用户的权限

            //如果有，token认证通过，放行

            //自动续期，请求进入到该位置，表示使用token，最后一次请求，当下
            //重新设置token的有效时间为30分钟

            redisTemplate.expire(key,30, TimeUnit.MINUTES);

            return true;
        }
        //如果没有，抛异常
        throw new TokenException("token失效");
    }
}
